"""
日志管理器模块

提供高级日志管理功能，包括日志过滤、分类、统计等
"""

import logging
import logging.handlers
import json
import time
from datetime import datetime, timedelta
from pathlib import Path
from typing import Dict, List, Optional, Any, Callable, Union
from dataclasses import dataclass, field
from collections import defaultdict, deque
from threading import Lock

from .logger import get_logger


@dataclass
class LogEntry:
    """日志条目"""
    timestamp: datetime
    level: str
    logger_name: str
    message: str
    module: str
    function: str
    line_number: int
    thread_id: int
    process_id: int
    extra_data: Dict[str, Any] = field(default_factory=dict)
    
    def to_dict(self) -> Dict[str, Any]:
        """转换为字典"""
        return {
            "timestamp": self.timestamp.isoformat(),
            "level": self.level,
            "logger_name": self.logger_name,
            "message": self.message,
            "module": self.module,
            "function": self.function,
            "line_number": self.line_number,
            "thread_id": self.thread_id,
            "process_id": self.process_id,
            "extra_data": self.extra_data
        }


class LogFilter:
    """日志过滤器"""
    
    def __init__(self):
        self.level_filters: List[str] = []
        self.module_filters: List[str] = []
        self.message_filters: List[str] = []
        self.time_range: Optional[tuple] = None
        self.custom_filters: List[Callable[[LogEntry], bool]] = []
    
    def add_level_filter(self, levels: Union[str, List[str]]):
        """添加日志级别过滤器"""
        if isinstance(levels, str):
            levels = [levels]
        self.level_filters.extend(levels)
    
    def add_module_filter(self, modules: Union[str, List[str]]):
        """添加模块过滤器"""
        if isinstance(modules, str):
            modules = [modules]
        self.module_filters.extend(modules)
    
    def add_message_filter(self, patterns: Union[str, List[str]]):
        """添加消息过滤器"""
        if isinstance(patterns, str):
            patterns = [patterns]
        self.message_filters.extend(patterns)
    
    def set_time_range(self, start_time: datetime, end_time: datetime):
        """设置时间范围过滤器"""
        self.time_range = (start_time, end_time)
    
    def add_custom_filter(self, filter_func: Callable[[LogEntry], bool]):
        """添加自定义过滤器"""
        self.custom_filters.append(filter_func)
    
    def matches(self, entry: LogEntry) -> bool:
        """检查日志条目是否匹配过滤条件"""
        # 级别过滤
        if self.level_filters and entry.level not in self.level_filters:
            return False
        
        # 模块过滤
        if self.module_filters:
            if not any(module in entry.module for module in self.module_filters):
                return False
        
        # 消息过滤
        if self.message_filters:
            if not any(pattern in entry.message for pattern in self.message_filters):
                return False
        
        # 时间范围过滤
        if self.time_range:
            start_time, end_time = self.time_range
            if not (start_time <= entry.timestamp <= end_time):
                return False
        
        # 自定义过滤器
        for custom_filter in self.custom_filters:
            if not custom_filter(entry):
                return False
        
        return True


class LogStatistics:
    """日志统计"""
    
    def __init__(self):
        self.level_counts: Dict[str, int] = defaultdict(int)
        self.module_counts: Dict[str, int] = defaultdict(int)
        self.hourly_counts: Dict[str, int] = defaultdict(int)
        self.error_patterns: Dict[str, int] = defaultdict(int)
        self.total_logs: int = 0
        self.start_time: Optional[datetime] = None
        self.end_time: Optional[datetime] = None
    
    def add_entry(self, entry: LogEntry):
        """添加日志条目到统计"""
        self.total_logs += 1
        self.level_counts[entry.level] += 1
        self.module_counts[entry.module] += 1
        
        # 按小时统计
        hour_key = entry.timestamp.strftime("%Y-%m-%d %H:00")
        self.hourly_counts[hour_key] += 1
        
        # 错误模式统计
        if entry.level in ["ERROR", "CRITICAL"]:
            # 简化错误消息作为模式
            pattern = entry.message.split(":")[0] if ":" in entry.message else entry.message
            self.error_patterns[pattern] += 1
        
        # 更新时间范围
        if self.start_time is None or entry.timestamp < self.start_time:
            self.start_time = entry.timestamp
        if self.end_time is None or entry.timestamp > self.end_time:
            self.end_time = entry.timestamp
    
    def get_summary(self) -> Dict[str, Any]:
        """获取统计摘要"""
        duration = None
        if self.start_time and self.end_time:
            duration = (self.end_time - self.start_time).total_seconds()
        
        return {
            "total_logs": self.total_logs,
            "level_distribution": dict(self.level_counts),
            "top_modules": dict(sorted(self.module_counts.items(), key=lambda x: x[1], reverse=True)[:10]),
            "error_rate": (self.level_counts["ERROR"] + self.level_counts["CRITICAL"]) / max(self.total_logs, 1),
            "logs_per_hour": dict(sorted(self.hourly_counts.items())),
            "top_error_patterns": dict(sorted(self.error_patterns.items(), key=lambda x: x[1], reverse=True)[:5]),
            "time_range": {
                "start": self.start_time.isoformat() if self.start_time else None,
                "end": self.end_time.isoformat() if self.end_time else None,
                "duration_seconds": duration
            }
        }


class MemoryLogHandler(logging.Handler):
    """内存日志处理器"""
    
    def __init__(self, max_entries: int = 10000):
        super().__init__()
        self.max_entries = max_entries
        self.entries: deque = deque(maxlen=max_entries)
        self.lock = Lock()
    
    def emit(self, record: logging.LogRecord):
        """发出日志记录"""
        try:
            with self.lock:
                entry = LogEntry(
                    timestamp=datetime.fromtimestamp(record.created),
                    level=record.levelname,
                    logger_name=record.name,
                    message=record.getMessage(),
                    module=record.module,
                    function=record.funcName,
                    line_number=record.lineno,
                    thread_id=record.thread,
                    process_id=record.process,
                    extra_data=getattr(record, 'extra_data', {})
                )
                self.entries.append(entry)
        except Exception:
            self.handleError(record)
    
    def get_entries(self, filter_obj: Optional[LogFilter] = None) -> List[LogEntry]:
        """获取日志条目"""
        with self.lock:
            entries = list(self.entries)
        
        if filter_obj:
            entries = [entry for entry in entries if filter_obj.matches(entry)]
        
        return entries
    
    def clear(self):
        """清空日志条目"""
        with self.lock:
            self.entries.clear()


class LogManager:
    """日志管理器"""
    
    def __init__(self, logger_name: Optional[str] = None):
        self.logger = get_logger(logger_name or __name__)
        self.memory_handler = MemoryLogHandler()
        self.statistics = LogStatistics()
        self.alert_rules: List[Dict[str, Any]] = []
        
        # 添加内存处理器到根日志记录器
        root_logger = logging.getLogger("gamer520")
        root_logger.addHandler(self.memory_handler)
    
    def add_alert_rule(
        self,
        name: str,
        condition: Callable[[LogEntry], bool],
        action: Callable[[LogEntry], None],
        cooldown_seconds: int = 60
    ):
        """
        添加日志告警规则
        
        Args:
            name: 规则名称
            condition: 触发条件函数
            action: 触发动作函数
            cooldown_seconds: 冷却时间（秒）
        """
        self.alert_rules.append({
            "name": name,
            "condition": condition,
            "action": action,
            "cooldown_seconds": cooldown_seconds,
            "last_triggered": None
        })
    
    def check_alerts(self, entry: LogEntry):
        """检查告警规则"""
        current_time = datetime.now()
        
        for rule in self.alert_rules:
            # 检查冷却时间
            if rule["last_triggered"]:
                time_since_last = (current_time - rule["last_triggered"]).total_seconds()
                if time_since_last < rule["cooldown_seconds"]:
                    continue
            
            # 检查触发条件
            if rule["condition"](entry):
                try:
                    rule["action"](entry)
                    rule["last_triggered"] = current_time
                    self.logger.info(f"触发告警规则: {rule['name']}")
                except Exception as e:
                    self.logger.error(f"执行告警动作失败: {rule['name']} - {str(e)}")
    
    def get_recent_logs(
        self,
        minutes: int = 60,
        level: Optional[str] = None,
        module: Optional[str] = None
    ) -> List[LogEntry]:
        """
        获取最近的日志
        
        Args:
            minutes: 最近多少分钟
            level: 日志级别过滤
            module: 模块过滤
            
        Returns:
            List[LogEntry]: 日志条目列表
        """
        filter_obj = LogFilter()
        
        # 时间过滤
        end_time = datetime.now()
        start_time = end_time - timedelta(minutes=minutes)
        filter_obj.set_time_range(start_time, end_time)
        
        # 级别过滤
        if level:
            filter_obj.add_level_filter(level)
        
        # 模块过滤
        if module:
            filter_obj.add_module_filter(module)
        
        return self.memory_handler.get_entries(filter_obj)
    
    def get_error_logs(self, hours: int = 24) -> List[LogEntry]:
        """获取错误日志"""
        filter_obj = LogFilter()
        filter_obj.add_level_filter(["ERROR", "CRITICAL"])
        
        end_time = datetime.now()
        start_time = end_time - timedelta(hours=hours)
        filter_obj.set_time_range(start_time, end_time)
        
        return self.memory_handler.get_entries(filter_obj)
    
    def generate_statistics(self, hours: int = 24) -> LogStatistics:
        """
        生成日志统计
        
        Args:
            hours: 统计最近多少小时的日志
            
        Returns:
            LogStatistics: 统计对象
        """
        stats = LogStatistics()
        
        # 获取指定时间范围的日志
        filter_obj = LogFilter()
        end_time = datetime.now()
        start_time = end_time - timedelta(hours=hours)
        filter_obj.set_time_range(start_time, end_time)
        
        entries = self.memory_handler.get_entries(filter_obj)
        
        for entry in entries:
            stats.add_entry(entry)
        
        return stats
    
    def export_logs(
        self,
        file_path: Union[str, Path],
        format_type: str = "json",
        filter_obj: Optional[LogFilter] = None
    ):
        """
        导出日志
        
        Args:
            file_path: 导出文件路径
            format_type: 导出格式 (json, csv, txt)
            filter_obj: 日志过滤器
        """
        file_path = Path(file_path)
        file_path.parent.mkdir(parents=True, exist_ok=True)
        
        entries = self.memory_handler.get_entries(filter_obj)
        
        if format_type.lower() == "json":
            with open(file_path, "w", encoding="utf-8") as f:
                json.dump([entry.to_dict() for entry in entries], f, indent=2, ensure_ascii=False)
        
        elif format_type.lower() == "csv":
            import csv
            with open(file_path, "w", newline="", encoding="utf-8") as f:
                if entries:
                    writer = csv.DictWriter(f, fieldnames=entries[0].to_dict().keys())
                    writer.writeheader()
                    for entry in entries:
                        writer.writerow(entry.to_dict())
        
        elif format_type.lower() == "txt":
            with open(file_path, "w", encoding="utf-8") as f:
                for entry in entries:
                    f.write(f"[{entry.timestamp}] {entry.level} {entry.logger_name}: {entry.message}\n")
        
        else:
            raise ValueError(f"不支持的导出格式: {format_type}")
        
        self.logger.info(f"导出 {len(entries)} 条日志到: {file_path}")
    
    def cleanup_old_logs(self, days: int = 30):
        """清理旧日志文件"""
        from config.settings import get_config
        
        config = get_config()
        log_dir = Path(config.logging.file).parent
        
        if not log_dir.exists():
            return
        
        cutoff_time = datetime.now() - timedelta(days=days)
        cleaned_count = 0
        
        for log_file in log_dir.glob("*.log*"):
            try:
                file_time = datetime.fromtimestamp(log_file.stat().st_mtime)
                if file_time < cutoff_time:
                    log_file.unlink()
                    cleaned_count += 1
            except Exception as e:
                self.logger.warning(f"清理日志文件失败: {log_file} - {str(e)}")
        
        if cleaned_count > 0:
            self.logger.info(f"清理了 {cleaned_count} 个旧日志文件")
    
    def get_log_health_status(self) -> Dict[str, Any]:
        """获取日志系统健康状态"""
        recent_logs = self.get_recent_logs(minutes=60)
        error_logs = self.get_error_logs(hours=1)
        
        return {
            "total_recent_logs": len(recent_logs),
            "recent_error_count": len(error_logs),
            "error_rate": len(error_logs) / max(len(recent_logs), 1),
            "memory_usage": len(self.memory_handler.entries),
            "memory_capacity": self.memory_handler.max_entries,
            "memory_usage_percent": len(self.memory_handler.entries) / self.memory_handler.max_entries * 100,
            "alert_rules_count": len(self.alert_rules),
            "last_log_time": recent_logs[-1].timestamp.isoformat() if recent_logs else None
        }


# 全局日志管理器实例
_global_manager: Optional[LogManager] = None


def get_log_manager() -> LogManager:
    """获取全局日志管理器"""
    global _global_manager
    if _global_manager is None:
        _global_manager = LogManager()
    return _global_manager


# 便捷函数
def get_recent_logs(minutes: int = 60, level: Optional[str] = None, module: Optional[str] = None) -> List[LogEntry]:
    """获取最近的日志"""
    return get_log_manager().get_recent_logs(minutes, level, module)


def get_error_logs(hours: int = 24) -> List[LogEntry]:
    """获取错误日志"""
    return get_log_manager().get_error_logs(hours)


def export_logs(file_path: Union[str, Path], format_type: str = "json", filter_obj: Optional[LogFilter] = None):
    """导出日志"""
    get_log_manager().export_logs(file_path, format_type, filter_obj)


def get_log_statistics(hours: int = 24) -> Dict[str, Any]:
    """获取日志统计"""
    return get_log_manager().generate_statistics(hours).get_summary()